package org.anachronos.jeep.ui.trace;

import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ICellEditorValidator;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.widgets.FormToolkit;

public class TraceTreePage extends TraceBasePage {
	private final TraceFilter traceFilter = new TraceFilter();
	private final int autoExpandLevel;
	private TreeViewer treeViewer;
	private ITreeContentProvider contentProvider;
	private Object input;
	private TraceViewerSorter sorter;

	public TraceTreePage(final FormEditor editor, final String id, final String title) {
		this(editor, id, title, 1);
	}

	public TraceTreePage(final FormEditor editor, final String id, final String title, final int autoExpandLevel) {
		super(editor, id, title);
		this.autoExpandLevel = autoExpandLevel;
	}

	protected void createFormContent(final IManagedForm managedForm) {
		final GridDataFactory gridDataFactory = 
			GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(true, true);
		
		final Composite body = managedForm.getForm().getBody();
		body.setLayout(new GridLayout(2, false));
		body.setLayoutData(gridDataFactory.create());
		
		final FormToolkit formToolkit = managedForm.getToolkit();
		
		final Composite treeParent = formToolkit.createComposite(body, SWT.NONE);
		final TreeColumnLayout treeColumnLayout = new TreeColumnLayout();
		treeParent.setLayout(treeColumnLayout);
		treeParent.setLayoutData(gridDataFactory.span(2, 1).create());
		
		final Tree tree = formToolkit.createTree(treeParent, SWT.NONE);
		tree.setHeaderVisible(true);
		treeViewer = new TreeViewer(tree);
		final TreeColumn nameColumn = createViewerColumn(treeViewer, "Name", SWT.LEFT, TraceFilterParser.NAME)
			.getColumn();
		treeColumnLayout.setColumnData(nameColumn, new ColumnWeightData(40, true));

		final TreeColumn invocationColumn = createViewerColumn(treeViewer, "Invocation", SWT.LEFT, TraceFilterParser.NAME)
			.getColumn();
		treeColumnLayout.setColumnData(invocationColumn, new ColumnWeightData(40, true));
		
		final TreeColumn selfMsColumn = createViewerColumn(treeViewer, "Self[ms]", SWT.RIGHT, TraceFilterParser.NUMERIC)
			.getColumn();
		treeColumnLayout.setColumnData(selfMsColumn, new ColumnWeightData(10, true));
		final TreeColumn selfPercentColumn = createViewerColumn(treeViewer, "Self[%]", SWT.RIGHT, TraceFilterParser.NUMERIC)
			.getColumn();
		tree.setSortColumn(selfPercentColumn);
		tree.setSortDirection(SWT.DOWN);
		treeColumnLayout.setColumnData(selfPercentColumn, new ColumnWeightData(7, true));
		
		final TreeColumn totalMsColumn = createViewerColumn(treeViewer, "Total[ms]", SWT.RIGHT, TraceFilterParser.NUMERIC)
			.getColumn();
		treeColumnLayout.setColumnData(totalMsColumn, new ColumnWeightData(10, true));
		final TreeColumn totalPercentColumn = createViewerColumn(treeViewer, "Total[%]", SWT.RIGHT, TraceFilterParser.NUMERIC)
			.getColumn();
		treeColumnLayout.setColumnData(totalPercentColumn, new ColumnWeightData(7, true));
		
		final TreeColumn callsColumn = createViewerColumn(treeViewer, "Calls", SWT.RIGHT, TraceFilterParser.NUMERIC)
			.getColumn();
		treeColumnLayout.setColumnData(callsColumn, new ColumnWeightData(10, true));
		
		treeViewer.setLabelProvider(new TraceLabelProvider());
		treeViewer.setContentProvider(contentProvider);
		treeViewer.setInput(input);
		treeViewer.setFilters(new ViewerFilter[] {traceFilter});
		sorter = new TraceViewerSorter();
		treeViewer.setSorter(sorter);
		treeViewer.setAutoExpandLevel(autoExpandLevel);
		
		registerContextMenu(treeViewer);
	}

	public void setContentProvider(final ITreeContentProvider contentProvider) {
		if (treeViewer != null) {
			treeViewer.setContentProvider(contentProvider);
		}
		this.contentProvider = contentProvider;
	}
	
	public void setInput(final Object input) {
		if (treeViewer != null) {
			treeViewer.setInput(input);
		}
		this.input = input;
	}
	
	public ViewerFilter getViewerFilter() {
		return traceFilter;
	}
	
	private TreeColumn createColumn(final Tree tree,
			final String columnName, final int style) {
		final TreeColumn column = new TreeColumn(tree, style);
		column.setText(columnName);
		column.addSelectionListener(new SelectionListener() {			
			@Override
			public void widgetSelected(SelectionEvent e) {
				final TreeColumn column = (TreeColumn) e.widget;
				final int sortDirection;
				if (tree.getSortColumn() == column) {
					switch (tree.getSortDirection()) {
					case SWT.UP:
						sortDirection = SWT.DOWN;
						break;
					default:
						sortDirection = SWT.UP;
					}
				} else {
					tree.setSortColumn(column);
					sortDirection = tree.getSortDirection();
				}
				tree.setSortDirection(sortDirection);
				
				final int indexOf = tree.indexOf(column);
				sorter.setSortColumnIndex(indexOf);
				sorter.setSortDirection(sortDirection);
				treeViewer.refresh();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});
		return column;
	}

	private TreeViewerColumn createViewerColumn(final TreeViewer treeViewer,
			final String columnName, final int style, final ICellEditorValidator cellEditorValidator) {
		final TreeColumn column = createColumn(treeViewer.getTree(), columnName, style);
		final TreeViewerColumn viewerColumn = new TreeViewerColumn(treeViewer, column);
		viewerColumn.setLabelProvider(new TraceLabelProvider());
		viewerColumn.setEditingSupport(new TraceFilterEditingSupport(treeViewer, cellEditorValidator));
		return viewerColumn;
	}
	
	@Override
	public Viewer getViewer() {
		return treeViewer;
	}
}
